import { deleteCodeGenerate, downloadCodeGenerate, generatePermissions, getCodeGenerateList, viewCodeGenerate } from "@/api/codeGenerate";
import { FormItemType, FormTableItemType } from "@/components/FormByData/FormByData";
import Table, { TableRef } from "@/components/Table";
import { Card, Space, Button, FormInstance, Tree, TreeDataNode, Tooltip, message, Popconfirm } from "antd";
import { Key, useRef, useState } from "react";
import { useNavigate } from "react-router";
import { formatDate } from "@/utils/date";
import { EditOutlined, CloudDownloadOutlined, FolderOutlined, FolderViewOutlined, AimOutlined, CopyOutlined, EyeOutlined, FileAddOutlined } from "@ant-design/icons";
import { CodeGenerate as CodeGenerateType, UpdateCodeGenerateReq } from "@/typings/api";
import Search from "@/components/Search";
import { Operations, ResultTypes } from "@/constant/codeGenerate";
import { copyText, downloadBlob } from "@/utils";
import Modal from "@/components/Modal/Modal";
import CodeMirror from "@uiw/react-codemirror";
import { javascript } from "@codemirror/lang-javascript";
import { vscodeLight } from "@uiw/codemirror-theme-vscode";

type SearchFields = Pick<CodeGenerateType, "modelName" | "collectionName">;

interface ExtendedTreeDataNode extends TreeDataNode {
    value?: string;
}

const CodeGenerate = () => {
    const navigate = useNavigate();
    const columns: FormTableItemType<UpdateCodeGenerateReq>[] = [
        { dataIndex: "modelName", title: "模型名" },
        { dataIndex: "pageName", title: "页面名", minWidth: 130 },
        { dataIndex: "collectionName", title: "集合名" },
        { dataIndex: "desc", title: "描述" },
        {
            dataIndex: "operations",
            title: "生成接口类型",
            isForm: false,
            minWidth: 400,
            render(operations) {
                return operations.map((operation: keyof typeof Operations) => Operations[operation]).join("，");
            },
        },
        {
            dataIndex: "resultTypes",
            title: "代码类型",
            minWidth: 130,
            render(resultTypes) {
                return resultTypes.map((resultType: keyof typeof ResultTypes) => ResultTypes[resultType]).join("，");
            },
        },
        { dataIndex: 'permissionKey', title: "权限标识" },
        { dataIndex: "createdAt", title: "创建时间", render: val => formatDate(val), isForm: false },
        { dataIndex: "updatedAt", title: "更新时间", render: val => formatDate(val), isForm: false },
        { dataIndex: "operation", isForm: false, fixed: "right", title: "操作" },
    ];

    const tableRef = useRef<TableRef>(null);

    const searchFormItems: FormItemType[] = [
        { label: "模型名", name: "modelName" },
        { label: "集合名", name: "collectionName" },
    ];
    const searchParams = useRef<Partial<CodeGenerateType>>({});
    const handleSearch = async (formData: SearchFields) => {
        searchParams.current = formData;
        await tableRef.current?.getList(1, 10);
    };

    const searchFromRef = useRef<FormInstance>();
    const handleReset = () => {
        searchFromRef.current?.resetFields();
        searchParams.current = {};
        tableRef.current?.getList(1, 10);
    };
    const [viewCodeId, setViewCodeId] = useState<string | null>(null);
    const [folderTreeData, setFolderTreeData] = useState<TreeDataNode[]>([]);

    const [expandedKeys, setExpandedKeys] = useState<Key[]>([]);
    const [selectedKeys, setSelectedKeys] = useState<Key[]>([]);
    const haveSetKeys = useRef(false);
    const [code, setCode] = useState<{ value: string; key: Key }>({ value: "", key: "" });
    const loopObjToTreeData = (obj: object, parentKey = ""): ExtendedTreeDataNode[] => {
        if (parentKey === "") {
            setExpandedKeys([]);
            setSelectedKeys([]);
            setCode({ value: "", key: "" });
            haveSetKeys.current = false;
        }
        return Object.entries(obj).map(([key, value]) => {
            const currentKey = parentKey ? `${parentKey}.${key}` : key;
            const obj: ExtendedTreeDataNode = {
                title: key,
                key: currentKey,
            };
            if (typeof value === "object") obj.children = loopObjToTreeData(value, currentKey);
            if (typeof value === "string") {
                obj.value = value;
                if (!haveSetKeys.current) {
                    setExpandedKeys([obj.key as string]);
                    setSelectedKeys([obj.key as string]);
                    setCode({ value, key: obj.key });
                    haveSetKeys.current = true;
                }
                obj.isLeaf = true;
            }
            return obj;
        });
    };

    const handleViewCodeGenerate = async (_id: string) => {
        setViewCodeId(_id);
        try {
            const { data } = await viewCodeGenerate(_id);
            const treeData = loopObjToTreeData(data);
            setFolderTreeData(treeData);
            setModalOpen(true);
        } finally {
            setViewCodeId(null);
        }
    };
    const handleCodeGenerate = async (_id: string) => {
        const blob = await downloadCodeGenerate(_id);
        downloadBlob(blob as Blob, `${_id}.zip`);
    };
    const [generatePermissionsLoadingIds, setGeneratePermissionsLoadingIds] = useState<string[]>([]);
    const handleGeneratePermissions = async (_id: string) => {
        setGeneratePermissionsLoadingIds([...generatePermissionsLoadingIds, _id]);
        try {
            await generatePermissions(_id);
            message.success("生成成功");
        } finally {
            setGeneratePermissionsLoadingIds(generatePermissionsLoadingIds.filter(id => id !== _id));
        }
    };
    const [modalOpen, setModalOpen] = useState(false);
    const getCodeFromTreeData = (key: Key, list: ExtendedTreeDataNode[]) => {
        const res = list.find(item => item.key === key);
        if (res) return res;
        let codeItem = null;
        list.some(item => {
            const res = getCodeFromTreeData(key, item.children || []);
            if (res) codeItem = res;
            return !!res;
        });
        return codeItem;
    };
    const treeSelect = (keys: Key[]) => {
        setSelectedKeys(keys);
        const res = getCodeFromTreeData(keys[0], folderTreeData);
        if (!res) return;
        const { value, key } = res;
        if (!value) return;
        setCode({ value, key });
    };
    const [codeHeight, setCodeHeight] = useState("500px");
    const [isExpandAllFolder, setIsExpandAllFolder] = useState(false);
    const handleExpandAllFolder = (bol: boolean) => {
        setIsExpandAllFolder(bol);
        if (!bol) return setExpandedKeys([]);
        const keys: Key[] = [];
        const loopTreeData = (list: TreeDataNode[]) => {
            list.forEach(item => {
                keys.push(item.key);
                if (item.children) loopTreeData(item.children);
            });
        };
        loopTreeData(folderTreeData);
        setExpandedKeys(keys);
    };
    return (
        <>
            <Card
                title={
                    <Search<SearchFields>
                        title="代码生成"
                        formItems={searchFormItems}
                        onReset={handleReset}
                        onAdd={() => navigate(`/system/codeGenerateConfig`)}
                        onSearch={handleSearch}
                        getFormRef={ref => (searchFromRef.current = ref)}
                    />
                }
            >
                <Table<UpdateCodeGenerateReq>
                    ref={tableRef}
                    columns={columns}
                    getApi={p => getCodeGenerateList({ ...p, ...searchParams.current })}
                    delApi={deleteCodeGenerate}
                    actionMore={record => (
                        <Space>
                            <Button
                                type="primary"
                                size="small"
                                icon={<EditOutlined />}
                                onClick={() => navigate(`/system/codeGenerateConfig?_id=${record._id}`)}
                            >
                                编辑
                            </Button>
                            <Button
                                type="primary"
                                size="small"
                                loading={viewCodeId === record._id}
                                icon={<EyeOutlined />}
                                onClick={() => handleViewCodeGenerate(record._id)}
                            >
                                查看
                            </Button>
                            <Button type="primary" size="small" icon={<CloudDownloadOutlined />} onClick={() => handleCodeGenerate(record._id)}>
                                下载
                            </Button>
                            <Popconfirm
                                title="确定要生成权限吗？"
                                okText="确定"
                                cancelText="取消"
                                onConfirm={() => handleGeneratePermissions(record._id)}
                            >
                                <Button loading={generatePermissionsLoadingIds.includes(record._id)} disabled={!record.permissionKey} type="primary" size="small" icon={<FileAddOutlined />}>生成权限</Button>
                            </Popconfirm>
                        </Space>
                    )}
                />
            </Card>
            <Modal
                title="查看代码"
                open={modalOpen}
                cancelButtonProps={{ style: { display: "none" } }}
                onCancel={() => setModalOpen(false)}
                onOk={() => setModalOpen(false)}
                width={1200}
                onFullChange={isFull => setCodeHeight(isFull ? "calc(100vh - 124px)" : "500px")}
                headAction={
                    <Button
                        icon={<CopyOutlined />}
                        type="text"
                        disabled={!code.value}
                        onClick={async () => {
                            await copyText(code.value);
                            message.success("复制成功");
                        }}
                    />
                }
            >
                <div className="flex justify-between items-start h-full">
                    <div style={{ height: codeHeight }} className="overflow-y-scroll no-scrollbar bg-gray-50 mr-4 p-1">
                        <Tooltip title={isExpandAllFolder ? "折叠全部" : "展开全部"}>
                            <Button
                                onClick={() => handleExpandAllFolder(!isExpandAllFolder)}
                                type="text"
                                icon={isExpandAllFolder ? <FolderOutlined /> : <FolderViewOutlined />}
                            />
                        </Tooltip>
                        <Tooltip title="定位文件">
                            <Button
                                icon={<AimOutlined />}
                                type="text"
                                onClick={() => {
                                    setExpandedKeys([code.key]);
                                    setSelectedKeys([code.key]);
                                }}
                            />
                        </Tooltip>
                        <Tree.DirectoryTree
                            className="overflow-y-scroll no-scrollbar bg-gray-50"
                            showIcon
                            treeData={folderTreeData}
                            style={{ width: 250 }}
                            selectedKeys={selectedKeys}
                            expandedKeys={expandedKeys}
                            autoExpandParent
                            onExpand={keys => setExpandedKeys(keys)}
                            onSelect={treeSelect}
                        />
                    </div>
                    <CodeMirror
                        className="flex-1"
                        value={code.value}
                        width={codeHeight === "500px" ? "870px" : "calc(100vw - 320px)"}
                        height={codeHeight}
                        extensions={[javascript({ jsx: true })]}
                        readOnly
                        theme={vscodeLight}
                    />
                </div>
            </Modal>
        </>
    );
};

export default CodeGenerate;
